package com.testingedu.utils;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Random;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.FileUploadBase.SizeLimitExceededException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.FileCleanerCleanup;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.io.FileCleaningTracker;

import com.testingedu.model.FileInfo;

/**
 * Servlet中使用的文件上传工具类
 * 
 * @author lsww
 * @E-mail lsww90@Gmail.com
 * @createtime 2012-11-24 下午04:11:42
 * @version 1.0
 * @since JDK 1.6
 */
public class FileUpLoad {
	private static final long serialVersionUID = -7674775871441129691L;
	private static final List<String> PICTURE_ALLOWED_EXT = new ArrayList<String>(); // 允许上传的文件类型image/png;image/jpeg;image/gif
	private static final long MAX_SIZE = 10 * 1024 * 1024;// 设置上传文件最大为 10M
	static {
		PICTURE_ALLOWED_EXT.add("image/png");
		PICTURE_ALLOWED_EXT.add("image/jpeg");
		PICTURE_ALLOWED_EXT.add("image/gif");
		PICTURE_ALLOWED_EXT.add("text/plain");
		PICTURE_ALLOWED_EXT.add("application/octet-stream");
		PICTURE_ALLOWED_EXT.add("application/vnd.openxmlformats-officedocument.wordprocessingml.document");//*.docx(office2010)
	}

	/**
	 * 将存放上传文件的临时目录设置为tomcat的temp文件夹下
	 * 
	 * @param request
	 * @return
	 */
	private static String getTempDirectory(ServletContext servletContext) {
		String path = servletContext.getRealPath("/");
		path = path.substring(0, path.length() - 1);
		path = path.substring(0, path.lastIndexOf(File.separator));
		path = path.substring(0, path.lastIndexOf(File.separator) + 1) + "temp";
		return path;
	}

	/**
	 * 
	 * @param req
	 * @param resp
	 * @param servletContext
	 * @param errorMessage
	 * @param bean
	 * @return
	 * @throws ServletException
	 * @throws IOException
	 */
	@SuppressWarnings("unchecked")
	public static synchronized String execute(HttpServletRequest req,
			HttpServletResponse resp, ServletContext servletContext, Object bean, FileInfo uploadFile, String saveDir)
			throws Exception {
		List<String> fileNames = new ArrayList<String>();
		List<String> fileContextType = new ArrayList<String>();
		List<File> files = new ArrayList<File>();
		// 得到清理放在硬盘上的临时文件处理实例
		FileCleaningTracker fileCleaningTracker = FileCleanerCleanup
				.getFileCleaningTracker(servletContext);
		// 实例化一个硬盘文件工厂,用来配置上传组件ServletFileUpload
		DiskFileItemFactory factory = new DiskFileItemFactory(4096, new File(
				getTempDirectory(servletContext)));
		factory.setFileCleaningTracker(fileCleaningTracker);
		// 用以上工厂实例化上传组件
		ServletFileUpload upload = new ServletFileUpload(factory);
		// 设置最大上传尺寸
		upload.setSizeMax(MAX_SIZE);
		upload.setHeaderEncoding("utf8");
		List<FileItem> fileList = null;
		String dbPath = null;
		try {
			fileList = upload.parseRequest(req);
		} catch (FileUploadException e) {// 处理文件尺寸过大异常
			e.printStackTrace();
			if (e instanceof SizeLimitExceededException) {
				req.setAttribute("message", "文件尺寸超过规定大小:" + MAX_SIZE + "字节");
				throw new Exception("文件尺寸超过规定大小:" + MAX_SIZE + "字节");
			}
		}
		// 没有文件上传
		if (fileList == null || fileList.size() == 0) {
			req.setAttribute("message", "请选择上传文件");
			throw new Exception();
		}
		// 得到所有上传的文件
		Iterator<FileItem> fileItr = fileList.iterator();
		// 循环处理所有文件
		while (fileItr.hasNext()) {
			FileItem fileItem = null;
			String path = null;
			long size = 0;
			// 得到当前文件
			fileItem = fileItr.next();
			if (fileItem == null) {
				continue;
			}
			if (fileItem.isFormField()) {// 将form表单中的值通过反射设置进相应的对象中
				String name = fileItem.getFieldName();
				String test = name;
				Class clazz = null;
				try {
					Field field = bean.getClass().getDeclaredField(name);
					clazz = field.getType();
				} catch (Exception e1) {
					e1.printStackTrace();
				}
				String value = fileItem.getString("UTF-8");
				if (name.length() == 1) {
					name = name.toUpperCase();
				} else {
					name = name.substring(0, 1).toUpperCase()
							+ name.substring(1, name.length());
				}
				if (value != null && value.trim().length() > 0) {
					try {
						Constructor con = clazz.getConstructor(String.class);
						Object o = con.newInstance(value);
						System.out.println("name:" + test + "  value:" + o);
						bean.getClass().getDeclaredMethod("set" + name,
								new Class[] { clazz }).invoke(bean, o);
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
				continue;
			}
			// 得到文件的完整路径
			path = fileItem.getName();
			// 得到文件的大小
			size = fileItem.getSize();
			if ("".equals(path) || size == 0) {
				req.setAttribute("message", "未选择上传文件");
				continue;
			}
			// 得到去除路径的文件名
			String fileName = path.substring(path.lastIndexOf("\\") + 1);
			// 得到文件的扩展名(无扩展名时将得到全名)
			String fileExt = fileName.substring(fileName.lastIndexOf(".") + 1);
			// 得到文件的类型
			String fileType = fileItem.getContentType();
			System.out.println(fileType);
			// 拒绝接受规定文件格式之外的文件类型
			if (!PICTURE_ALLOWED_EXT.contains(fileType)) {
				StringBuffer sb = new StringBuffer("请上传以下类型的文件<p />");
				for (String str : PICTURE_ALLOWED_EXT) {
					sb.append("*." + str + "&nbsp;&nbsp;&nbsp;");
				}
				req.setAttribute("message", sb.toString());
				throw new Exception();
			}
			// 根据系统时间生成上传后保存的文件名
			String prefix = String.valueOf(System.currentTimeMillis()) +"_"+new Random().nextInt(1000) + "."
					+ fileExt;
			dbPath = saveDir +File.separator+ prefix;
			File directory = new File(servletContext
					.getRealPath(File.separator)
					+ saveDir);
			if (!directory.exists()) {
				directory.mkdirs();
			}
			// 保存的最终文件完整路径
			String finalFileName = directory.getAbsolutePath() + File.separator
					+ prefix;
			try {
				// 保存文件
				File file = new File(finalFileName);
				fileItem.write(file);
				files.add(file);
				System.out
						.println("文件上传成功. 已保存为: " + finalFileName + "   文件大小: "
								+ size + "字节        " + "文件类型：" + fileExt);
			} catch (Exception e) {
				e.printStackTrace();
			}
			fileContextType.add(fileType);
			fileNames.add(prefix);
		}
		if (files.size() > 0) {
			File[] _a = new File[1];
			uploadFile.setFile(files.toArray(_a));
			String[] _b = new String[1];
			uploadFile.setContentType(fileContextType.toArray(_b));
			uploadFile.setName(fileNames.toArray(_b));
		}
		return dbPath;
	}

}
